#ifndef __DYNAMICQUANTICE_H__
#define __DYNAMICQUANTICE_H__

// #include <opencv2/dnn/dnn.hpp>
// #include <opencv2/opencv.hpp>

#include <opencv2/dnn.hpp>
#include <opencv2/dnn/shape_utils.hpp>    // getPlane

#include <opencv2/dnn/layer.details.hpp>  // CV_DNN_REGISTER_LAYER_CLASS
using namespace cv;
using namespace std;

class DynamicQuantizeLinearLayer CV_FINAL: public cv::dnn::Layer {
    public:
        static Ptr<Layer> create (const cv::dnn::LayerParams &params) {
            return Ptr<Layer> (new DynamicQuantizeLinearLayer (params));
        }

        DynamicQuantizeLinearLayer (const cv::dnn::LayerParams &params)
            : Layer (params) {}

        virtual bool getMemoryShapes (const vector<vector<int>> &inputs, const int requiredOutputs,
            vector<vector<int>> &outputs, vector<vector<int>> &internals) const override {
            // 输入: 1个浮点张量 [batch, channels, height, width]
            CV_CheckEQ (inputs.size (), (size_t)1, "DQL: 需要1个输入");

            // 输出:
            // 1. 量化数据 (UINT8, 同输入形状)
            // 2. 缩放因子 (标量)
            // 3. 零点 (标量)
            outputs.resize (3);
            outputs[0] = inputs[0]; // 量化数据形状同输入
            outputs[1] = {1};       // 缩放因子 (标量)
            outputs[2] = {1};       // 零点 (标量)

            return false;
        }

        virtual void forward (InputArrayOfArrays inputs_arr, OutputArrayOfArrays outputs_arr,
            OutputArrayOfArrays internals_arr) override {
            // 获取输入张量
            vector<Mat> inputs, outputs;
            inputs_arr.getMatVector (inputs);
            outputs_arr.getMatVector (outputs);

            CV_CheckEQ (inputs.size (), (size_t)1, "DQL: 需要1个输入");
            CV_CheckEQ (outputs.size (), (size_t)3, "DQL: 需要3个输出");

            const Mat &input = inputs[0];
            Mat       &quantized = outputs[0];
            Mat       &scale = outputs[1];
            Mat       &zero_point = outputs[2];

            // 确保输入是浮点类型
            CV_CheckTypeEQ (input.type (), CV_32F, "DQL: 输入必须是 CV_32F");

            // 步骤1: 计算输入张量的最小值和最大值
            double minVal, maxVal;
            minMaxLoc (input, &minVal, &maxVal);

            // 步骤2: 计算缩放因子和零点
            float fscale = (maxVal - minVal) / 255.0f;
            if (fscale == 0)
                fscale = 1.0f; // 防止除零

            uint8_t zp = static_cast<uint8_t> (std::round (-minVal / fscale));
            zp = std::max (0, std::min (255, (int)zp)); // 钳制到[0,255]范围

            // 存储计算结果
            scale.at<float> (0) = fscale;
            zero_point.at<uint8_t> (0) = zp;

            // 步骤3: 执行量化 (浮点到UINT8)
            quantized.create (input.size (), CV_8U);

            const float *inPtr = input.ptr<float> ();
            uint8_t     *outPtr = quantized.ptr<uint8_t> ();

            int total = input.total ();
            for (int i = 0; i < total; ++i) {
                float val = (inPtr[i] / fscale) + zp;
                outPtr[i] = saturate_cast<uint8_t> (std::round (val));
            }
        }
};
#endif // __DYNAMICQUANTICE_H__
